package com.joizhang.seckill.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.joizhang.seckill.api.redis.GoodsKey;
import com.joizhang.seckill.api.redis.OrderKey;
import com.joizhang.seckill.api.service.GoodsService;
import com.joizhang.seckill.api.vo.GoodsVo;
import com.joizhang.seckill.api.vo.SecKillGoodsVo;
import com.joizhang.seckill.mapper.GoodsMapper;
import com.joizhang.seckill.mapper.SecKillGoodsMapper;
import com.joizhang.seckill.model.Goods;
import com.joizhang.seckill.model.SecKillGoods;
import com.joizhang.seckill.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@DubboService
@Service
@Slf4j
public class GoodsServiceImpl implements GoodsService {

    private final RedisService redisService;

    private final GoodsMapper goodsMapper;

    private final SecKillGoodsMapper secKillGoodsMapper;

    @Autowired
    public GoodsServiceImpl(RedisService redisService, GoodsMapper goodsMapper, SecKillGoodsMapper secKillGoodsMapper) {
        this.redisService = redisService;
        this.goodsMapper = goodsMapper;
        this.secKillGoodsMapper = secKillGoodsMapper;
    }

    @Override
    public Boolean initRedis() {
        // 删除订单缓存
        Set<String> orderKeys = redisService.keys(OrderKey.SECKILL_ORDER, "*");
        if (CollectionUtils.isNotEmpty(orderKeys)) {
            log.warn("delete orders...");
            redisService.deleteKeys(orderKeys);
        }
        List<GoodsVo> goodsVoList = this.getGoodsVos();
        if (CollectionUtils.isEmpty(goodsVoList)) {
            return false;
        }
        List<SecKillGoodsVo> secKillGoodsVoList = this.getSecKillGoodsVos(goodsVoList);
        for (SecKillGoodsVo secKillGoodsVo : secKillGoodsVoList) {
            redisService.setZSet(GoodsKey.GOODS_LIST, "", secKillGoodsVo.getId(), Double.valueOf(secKillGoodsVo.getId()));
            JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(secKillGoodsVo));
            redisService.setHashAll(GoodsKey.GOODS_DETAIL, secKillGoodsVo.getGoodsId().toString(), jsonObject);
            redisService.set(GoodsKey.GOODS_STOCK, secKillGoodsVo.getId().toString(), secKillGoodsVo.getStockCount());
        }
        return true;
    }

    @Override
    public GoodsVo getGoodsVoByGoodsId(Long goodsId) {
        GoodsVo goodsVo = new GoodsVo();
        Goods goods = goodsMapper.getGoodsByGoodsId(goodsId);
        BeanUtils.copyProperties(goods, goodsVo);
        return goodsVo;
    }

    @Override
    public SecKillGoodsVo getSecKillGoodsVoByGoodsId(Long goodsId) {
        SecKillGoodsVo secKillGoodsVo = new SecKillGoodsVo();
        Goods goods = goodsMapper.getGoodsByGoodsId(goodsId);
        BeanUtils.copyProperties(goods, secKillGoodsVo);
        SecKillGoods secKillGoods = secKillGoodsMapper.getSecKillGoodsByGoodsId(goodsId);
        BeanUtils.copyProperties(secKillGoods, secKillGoodsVo);
        return secKillGoodsVo;
    }

    @Override
    public List<GoodsVo> getGoodsVos() {
        List<GoodsVo> goodsVos = new ArrayList<>();
        List<Goods> goodsList = goodsMapper.getGoodsList();
        for (Goods goods : goodsList) {
            GoodsVo goodsVo = new GoodsVo();
            BeanUtils.copyProperties(goods, goodsVo);
            goodsVos.add(goodsVo);
        }
        return goodsVos;
    }

    @Override
    public List<SecKillGoodsVo> getSecKillGoodsVos(List<GoodsVo> goodsVoList) {
        List<Long> goodsIds = new ArrayList<>(goodsVoList.size());
        HashMap<Long, GoodsVo> goodsVoHashMap = new HashMap<>();
        for (GoodsVo goodsVo : goodsVoList) {
            goodsIds.add(goodsVo.getId());
            goodsVoHashMap.put(goodsVo.getId(), goodsVo);
        }
        List<SecKillGoodsVo> secKillGoodsVoList = new ArrayList<>(goodsIds.size());
        List<SecKillGoods> secKillGoodsList = secKillGoodsMapper.getSecKillGoodsListByGoodsIds(goodsIds);
        for (SecKillGoods secKillGoods : secKillGoodsList) {
            GoodsVo goodsVo = goodsVoHashMap.get(secKillGoods.getGoodsId());
            SecKillGoodsVo secKillGoodsVo = new SecKillGoodsVo();
            BeanUtils.copyProperties(goodsVo, secKillGoodsVo);
            BeanUtils.copyProperties(secKillGoods, secKillGoodsVo);
            secKillGoodsVoList.add(secKillGoodsVo);
        }
        return secKillGoodsVoList;
    }

    @Override
    public List<Long> getGoodsIdsFromCache() {
        List<Object> objectList = redisService.getZSet(GoodsKey.GOODS_LIST, "");
        if (CollectionUtils.isEmpty(objectList)) {
            synchronized (this) {
                objectList = redisService.getZSet(GoodsKey.GOODS_LIST, "");
                if (CollectionUtils.isEmpty(objectList)) {
                    initRedis();
                    objectList = redisService.getZSet(GoodsKey.GOODS_LIST, "");
                }
            }
        }
        List<Long> goodsIds = new ArrayList<>();
        if (!CollectionUtils.isEmpty(objectList)) {
            for (Object object : objectList) {
                goodsIds.add(Long.valueOf(object.toString()));
            }
        }
        return goodsIds;
    }

    @Override
    public SecKillGoodsVo getGoodsDetailFromCache(Long goodsId) {
        JSONObject jsonObject = redisService.getHashAll(GoodsKey.GOODS_DETAIL, goodsId.toString());
        if (jsonObject.isEmpty()) {
            return null;
        }
        return JSONObject.toJavaObject(jsonObject, SecKillGoodsVo.class);
    }

    @Override
    public void setStock(GoodsKey goodsStock, String key, Integer stockCount) {
        redisService.set(GoodsKey.GOODS_STOCK, key, stockCount);
    }

}
